Creating HTML User Interfaces for Server Programs
by Michael Janulaitis
Example 1:
LoadModule acme_module modules/AcmeModule.dll
SetHandler acme-handler
acmeServerHost localhost
acmeServerPort 28500
Listing One
/* The sample code provided is for Windows only */
/* main.c */
#include
#include
#include
#include "acmeprotocol.h"
/* user entry which contains a key and a name */
typedef struct {
DWORD key;
char *user;
char *pswd;
}USER_T;
/* static list that contains three users */
static USER_T users[] = {
{ 0xFFFFFFFF, "Manny", "manny" },
{ 0xFFFFFFFF, "Moe", "moe" },
{ 0xFFFFFFFF, "Jack", "jack" }
};
int main(int argc, char **argv) {
ACMEPROTOCOL_T command, response;
BOOL bQuit = FALSE;
BYTE *pbt;
char input, packet[256], *pswd, *user;
DWORD key, localkey = 0, *pdw;
int fromlen, i, rc;
FD_SET fdsErr, fdsRead, fdSet;
struct sockaddr_in from, local;
SOCKET s, msgsock;
SYSTEMTIME ts;
struct timeval t = { 1, 0};
WORD *pw;
WSADATA wsadata;
/* create the server */
if (WSAStartup(MAKEWORD(2,2), &wsadata))
return -1;
local.sin_family = AF_INET;
local.sin_port = htons(28500);
local.sin_addr.s_addr = htonl(INADDR_ANY);
s = socket(AF_INET, SOCK_STREAM, 0);
if(INVALID_SOCKET == s) {
WSACleanup(); return -1;
}
if (bind(s,(struct sockaddr*)&local,sizeof(local) ) == SOCKET_ERROR)
bQuit = TRUE;
if (listen(s,SOMAXCONN) == SOCKET_ERROR)
bQuit = TRUE;
FD_ZERO(&fdSet);
FD_SET(s, &fdSet);
while(!bQuit) {
while(!kbhit()) {
memcpy((void*)&fdsRead,(void*)&fdSet, sizeof(fd_set));
memcpy((void*)&fdsErr, (void*)&fdSet, sizeof(fd_set));
rc = select(0, &fdsRead, NULL, &fdsErr, &t);
if (SOCKET_ERROR == rc) {
bQuit = TRUE;
break;
}
if (!rc)
continue;
if (FD_ISSET(s, &fdsErr)) {
bQuit = TRUE;
break;
}
if (!FD_ISSET(s, &fdsRead))
continue;
fromlen = sizeof(from);
msgsock = accept(s,(struct sockaddr*)&from, &fromlen);
if (msgsock == INVALID_SOCKET) {
bQuit = TRUE;
break;
}
/* Get the command. Note that the data must be sent in one
packet otherwise this program will fail. This program also
assumes the correct data is sent. You will need to write a packet
handler to deal with these issues */
rc = recv(msgsock,packet,sizeof(packet),0 );
if (SOCKET_ERROR != rc && rc &&
rc >= sizeof(ACMEPROTOCOL_T) + sizeof(DWORD)) {
/* handle the command */
pbt = packet;
pw = (WORD*)pbt;
command.cmd = (WORD)ntohs(*pw);
pbt += sizeof(WORD);
pw = (WORD*)pbt;
command.status = (WORD)ntohs(*pw);
pbt += sizeof(WORD);
pdw = (DWORD*)pbt;
command.size = (DWORD)ntohl(*pdw);
pbt += sizeof(DWORD);
pdw = (DWORD*)pbt;
key = (DWORD)ntohl(*pdw);
pbt += sizeof(DWORD);
response.cmd = command.cmd;
response.status = 0;
response.size = 0;
switch (command.cmd)
{
case CMD_LOGIN:
user = pbt; /* protocol handler required */
pbt += strlen(user) + 1;
pswd = pbt; /* protocol handler required */
for (i = 0; i < 3; i++) {
if (!strcmp(users[i].user, user)) {
if (!strcmp(users[i].pswd, pswd)) {
users[i].key = ++localkey;
pbt = packet;
pbt += sizeof(ACMEPROTOCOL_T);
pdw = (DWORD*)pbt;
*pdw = htonl(users[i].key);
response.size = sizeof(DWORD);
response.status = 1;
}
break;
}
}
break;
case CMD_LOGOUT:
for (i = 0; i < 3; i++) {
if (users[i].key == key) {
users[i].key = 0xFFFFFFFF;
response.status = 1;
break;
}
}
break;
case CMD_GETTIME:
for (i = 0; i < 3; i++) {
if (users[i].key == key) {
GetSystemTime(&ts);
pbt = packet;
pbt += sizeof(ACMEPROTOCOL_T);
_snprintf(pbt,
sizeof(packet) - sizeof(ACMEPROTOCOL_T),
"%02d:%02d:%02d", ts.wHour, ts.wMinute, ts.wSecond);
pbt[sizeof(packet) - sizeof(ACMEPROTOCOL_T) - 1] = 0;
response.size = strlen(pbt) + 1;
response.status = 1;
break;
}
}
break;
}
pbt = packet;
pw = (WORD*)pbt;
*pw = htons(response.cmd);
pbt += sizeof(WORD);
pw = (WORD*)pbt;
*pw = htons(response.status);
pbt += sizeof(WORD);
pdw = (DWORD*)pbt;
*pdw = htonl(response.size);
pbt += sizeof(DWORD);
send(msgsock,packet,sizeof(ACMEPROTOCOL_T) + response.size,0);
}
closesocket(msgsock);
}
input = getch();
if (input == 'q')
break;
}
closesocket(s);
WSACleanup();
return 0;
}
/* acmdprotocol.h */
#ifndef ACMEPROTOCOL_H
#define ACMEPROTOCOL_H
typedef struct {
WORD cmd;
WORD status;
DWORD size;
}ACMEPROTOCOL_T;
typedef enum {
CMD_LOGIN, CMD_LOGOUT, CMD_GETTIME,
}CMD;
#endif
Listing Two
static char g_host[256];
static WORD g_port = 28500;
BOOL CAcmeISAPIFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
{
// Call default implementation for initialization
CHttpFilter::GetFilterVersion(pVer);
// Clear the flags set by base class
pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK;
// Set the flags we are interested in
pVer->dwFlags |= SF_NOTIFY_ORDER_LOW | SF_NOTIFY_SECURE_PORT |
SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_PREPROC_HEADERS;
// Load description string
TCHAR sz[SF_MAX_FILTER_DESC_LEN+1];
ISAPIVERIFY(::LoadString(AfxGetResourceHandle(),
IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN));
_tcscpy(pVer->lpszFilterDesc, sz);
DWORD port, type, size;
HKEY hKey;
g_host[0] = 0;
// Open the registry
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE,
_T("software\\acme"), 0, KEY_READ, &hKey))
return FALSE;
// Get the server application host
size = sizeof(g_host);
if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("host"),
0, &type, (BYTE*)&g_host, &size)) {
RegCloseKey(hKey);
return FALSE;
}
// Get the mas port
size = sizeof(port);
if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("port"),
0, &type, (BYTE*)&port, &size)) {
RegCloseKey(hKey);
return FALSE;
}
g_port = (WORD)port;
// Close the registry
RegCloseKey(hKey);
return TRUE;
}
Listing Three
DWORD CAcmeISAPIFilter::OnPreprocHeaders(CHttpFilterContext* pfc,
PHTTP_FILTER_PREPROC_HEADERS pHeaders)
{
TCHAR url[256], newurl[256], *test;
DWORD size = sizeof(url);
if (pHeaders->GetHeader(pfc->m_pFC,_T("URL"),url,&size)) {
test = _tcsstr(url, _T("/acme"));
if (test) {
test += _tcslen(_T("/acme"));
if (test[0]) {
_sntprintf(newurl, 256, _T("/Scripts/AcmeISAPI.dll%s"), test);
newurl[255] = 0;
} else
_tcscpy(newurl, _T("/Scripts/AcmeISAPI.dll"));
pHeaders->SetHeader(pfc->m_pFC, _T("URL"), newurl);
}
}
return CHttpFilter::OnPreprocHeaders(pfc, pHeaders);
}
5